package mth;

public class Node implements Comparable<Node>{
//	private static Node[][] neighborhoods = new Node[0][];
	private int number;
	private int predecessorEdgeCount;
	private int successorEdgeCount;
	private Node[] successors;
	private Node[] predecessors;
//	private int neighborhood;
	private int x;
	private int y;
	private int stage;
	private int upperBound;
	private int lowerBound;
	
	public Node(int num) {
		number=num;
		predecessorEdgeCount=0;
		successorEdgeCount=0;
		x=0;
		y=0;
		stage=-1;
		upperBound=-1;
		lowerBound=-1;
		
		successors= new Node[0];
		predecessors=new Node[0];
//		neighborhood=createNeighborhood(this);
	}
	
	//private------------------------------------------------
	
	private void incrementPredecessors() {
		predecessorEdgeCount++;
	}
	
	private void incrementSuccessors() {
		successorEdgeCount++;
	}
	
//	private void setNeighborhood(int new_neighborhood) {
//		neighborhood=new_neighborhood;
//	}
	
//	//adds Nodes, which should be drawn beside the actual node
//	private void addNeighbor(Node n) {
////		//TODO: catch that a predecessor and his successors can�t be in a neighborhood!
////		//can I use the following lines for this task?...think about it later
////		boolean areConnected=false;
////		for (int a=0; a<getSuccessors().length;a++)
////			if (getSuccessors()[a].getNumber()==arg0.getNumber())
////				areConnected=true;
////		for (int a=0; a<arg0.getSuccessors().length;a++)
////			if (arg0.getSuccessors()[a].getNumber()==getNumber())
////				areConnected=true;
////		if (!areConnected)
////			addNeighbor(n);
//		
//		//if own node has no neighborhood:
//		if (getNeighborhood()==-1) {
//			if (n.getNeighborhood()==-1) {
//				//both have no neighborhood --> create a new one
//				createNeighborhood(this, n);
//				return;
//			} else {
//				//add this node to the neighborhood of n
//				n.addNeighbor(this);
//				return;
//			}
//		} else {
//			//check if neighbor exists already
//			//a) in own neighborhood --> return with no action
//			for (int a=0; a<neighborhoods[getNeighborhood()].length; a++) {
//				if (neighborhoods[getNeighborhood()][a].equals(n))
//					return;
//			}
//			//b) in a different neighborhood --> combine neighborhoods and return
//			for (int a=0; a<neighborhoods.length; a++) {
//				for (int b=0; b<neighborhoods[a].length; b++) {
//					if (neighborhoods[a][b].equals(n) && a!=getNeighborhood()) {
//						combineNeighborhoods(getNeighborhood(),a);
//						return;
//					}
//				}
//			}
//		
//			//neighbor does not exist yet, none of the above return statements
//			//was hit and we can continue without an additional if/for pattern
//			//now we add the actual node to out neighborhood
//			Node []helper=new Node[neighborhoods[getNeighborhood()].length+1];
//			for (int a=0; a<neighborhoods[getNeighborhood()].length; a++) {
//				helper[a]=neighborhoods[getNeighborhood()][a];
//			}
//			//because we add n to our actual neighborhood, we have to update its
//			//neighborhood membership
//			n.setNeighborhood(getNeighborhood());
//			helper[neighborhoods[getNeighborhood()].length]=n;
//			neighborhoods[getNeighborhood()]=new Node[helper.length];
//			for (int b=0; b<helper.length; b++) {
//				neighborhoods[getNeighborhood()][b]=helper[b];
//			}
//		}
//	}
	
//	private int createNeighborhood(Node n1) {
//		if (neighborhoods.length==0) {
//			neighborhoods = new Node [1][1];
//			neighborhoods[0][0] = n1;
//			n1.setNeighborhood(neighborhoods.length-1);
//		} else {
//			Node[][] helper = new Node[neighborhoods.length+1][];
//			for (int a=0; a<neighborhoods.length; a++) {
//				helper[a] = new Node[neighborhoods[a].length];
//				helper[a] = neighborhoods[a];
//			}
//			helper[neighborhoods.length] = new Node[1];
//			helper[neighborhoods.length][0] = n1;
//			n1.setNeighborhood(neighborhoods.length);
//			neighborhoods = new Node[helper.length][];
//			for (int a=0; a<helper.length; a++) {
//				neighborhoods[a] = new Node[helper[a].length];
//				neighborhoods[a] = helper[a];
//			}
//		}
//		return n1.getNeighborhood();
//	}
	
//	private void createNeighborhood(Node n1, Node n2) {
//		if (neighborhoods.length==0) {
//			//create the first neighborhood of all
//			//should never be used, because every node gets its own
//			//neighborhood by initialization
//			neighborhoods = new Node[1][2];
//			neighborhoods[0][0]=n1;
//			neighborhoods[0][0].setNeighborhood(0);
//			neighborhoods[0][1]=n2;
//			neighborhoods[0][1].setNeighborhood(0);
//		} else {
//			//we have to add a new neighborhood at the end
//			Node[][] helper = new Node[neighborhoods.length+1][];
//			for (int a=0; a<neighborhoods.length; a++) {
//				helper[a] = new Node[neighborhoods[a].length];
//				helper[a] = neighborhoods[a];
//			}
//			helper[neighborhoods.length] = new Node[2];
//			helper[neighborhoods.length][0]=n1;
//			helper[neighborhoods.length][0].setNeighborhood(neighborhoods.length);
//			helper[neighborhoods.length][1]=n2;
//			helper[neighborhoods.length][1].setNeighborhood(neighborhoods.length);
//			neighborhoods = new Node[helper.length][];
//			for (int a=0; a<helper.length; a++) {
//				neighborhoods[a]=helper[a];
//			}
//		}
//	}
	
//	private void combineNeighborhoods(int n1, int n2) {		
//		//copy all new neighbors to helper for temporary storing
//		Node[] helper = new Node[neighborhoods[n1].length+neighborhoods[n2].length];
//		for (int a=0; a<(neighborhoods[n1].length+neighborhoods[n2].length); a++) {
//			if (a<neighborhoods[n1].length)
//				helper[a]=neighborhoods[n1][a];
//			else
//				helper[a]=neighborhoods[n2][a-neighborhoods[n1].length];
//		}
//		//get new space at n1
//		neighborhoods[n1] = new Node[helper.length];
//		//copy back and update new neighborhood
//		for (int a=0; a<helper.length; a++) {
//			neighborhoods[n1][a]=helper[a];
//			neighborhoods[n1][a].setNeighborhood(n1);
//		}
//		//rearrange the neighborhoods to avoid empty neighborhoods which cause damage
//		//to the subdivision of the canvas
//		//to be sure as a first step we NULL the neighborhood n2
//		neighborhoods[n2]=null;
//		//then rearranging:
//		//a) n2 was the last neighborhood in the array
//		if (n2==neighborhoods.length-1) {
//			Node[][] helper2 = new Node[neighborhoods.length-1][];
//			for (int a=0; a<helper2.length; a++) {
//				helper2[a] = new Node[neighborhoods[a].length];
//				helper2[a] = neighborhoods[a];
//			}
//			neighborhoods = new Node[helper2.length][];
//			for (int a=0; a<helper2.length; a++) {
//				neighborhoods[a] = new Node[helper2[a].length];
//				neighborhoods[a] = helper2[a];
//			}
//		} else {
//		//b) n2 was not the last neighborhood in the array
//			neighborhoods[n2] = new Node[neighborhoods[neighborhoods.length-1].length];
//			neighborhoods[n2] = neighborhoods[neighborhoods.length-1];
//			//because i am not sure if the following works:
//			//neighborhoods[neighborhoods.length-1]=null;
//			//i use a for-loop again to be safe...
//			Node[][] helper2 = new Node[neighborhoods.length-1][];
//			for (int a=0; a<helper2.length; a++) {
//				helper2[a] = new Node[neighborhoods[a].length];
//				helper2[a] = neighborhoods[a];
//			}
//			neighborhoods = new Node[helper2.length][];
//			for (int a=0; a<helper2.length; a++) {
//				neighborhoods[a] = new Node[helper2[a].length];
//				neighborhoods[a] = helper2[a];
//				//and updating the neighborhood-memberships 
//				//to complete the task for each neighborhood
//				for (int b=0; b<neighborhoods[a].length; b++)
//					neighborhoods[a][b].setNeighborhood(a);
//			}
//		}
//	}
	
	//public--------------------------------------------------
	
	public int getNumber() {
		return number;
	}
	
	public int getPredecessorEdgeCount() {
		return predecessorEdgeCount;
	}
	
	public int getSuccessorEdgeCount() {
		return successorEdgeCount;
	}
	
	public int getX() {
		return x;
	}
	
	public int getY() {
		return y;
	}
	
	public Node[] getSuccessors() {
		return successors;
	}
	
	public Node[] getPredecessors() {
		return predecessors;
	}
	
	public int getEdgeCount() {
		return predecessorEdgeCount+successorEdgeCount;
	}
	
//	public int getNeighborhood() {
//		return neighborhood;
//	}
//	
//	public Node[] getNeighbors() {
//		return neighborhoods[getNeighborhood()];
//	}
//	
//	public int getNeighborhoodSize() {
//		return neighborhoods[getNeighborhood()].length;
//	}
//	
//	public Node[][] getAllNeighborhoods() {
//		return neighborhoods;
//	}
//	
//	public int getNumberOfAllNeighborhoods() {
//		return neighborhoods.length;
//	}
	
	public int getStage() {
		return stage;
	}
	
	public int getUpperBound() {
		return upperBound;
	}
	
	public int getLowerBound() {
		return lowerBound;
	}
	
	//@param: predecessorsToTest: the predecessors Array of a Node
	//this method finds the predecessor with the lowest number
	public Node getSmallestPredecessor(Node[] predecessorsToTest) {
		if (predecessorsToTest.length==0) {
			return null;
		}
		Node helper = predecessorsToTest[0];
		for (int a=0; a<(predecessorsToTest.length-1); a++) {
			if (predecessorsToTest[a].number<predecessorsToTest[a+1].number)
				helper=predecessorsToTest[a];
		}
		return helper;
	}
	
	//@param: predecessorsToTest: the predecessors Array of a Node
	//this method finds the predecessor with the highest number
	public Node getBiggestPredecessor(Node[] predecessorsToTest) {
		if (predecessorsToTest.length==0) {
			return null;
		}
		Node helper = predecessorsToTest[0];
		for (int a=0; a<(predecessorsToTest.length-1); a++) {
			if (predecessorsToTest[a].number>predecessorsToTest[a+1].number)
				helper=predecessorsToTest[a];
		}
		return helper;
	}
	
	public void setX(int x_new) {
		x=x_new;
	}
	
	public void setY(int y_new) {
		y=y_new;
	}
	
	public void setXY (int x_new, int y_new) {
		x=x_new;
		y=y_new;
	}
	
	public void setStage (int s) {
		stage=s;
	}
	
	public void setUpperBound(int u) {
		upperBound=u;
	}
	
	public void setLowerBound(int l) {
		lowerBound=l;
	}
	
	public void setPredecessor(Node from) {
		if (predecessorEdgeCount==0) {
			predecessors=new Node[1];
			predecessors[0]=from;
		} else {
			Node []helper=new Node[predecessors.length+1];
			for (int a=0; a<predecessors.length; a++) {
				helper[a]=predecessors[a];
			}
			helper[predecessors.length]=from;
			predecessors=new Node[helper.length];
			for (int b=0; b<helper.length; b++) {
				predecessors[b]=helper[b];
			}
		}
		incrementPredecessors();
	}
	
	public void deletePredecessor(Node from) {
		if (predecessorEdgeCount==0 || predecessors.length==0) {
			return;
		} else {
			boolean contains=false;
			Node []helper = new Node[predecessors.length-1];
			for (int a=0; a<predecessors.length;a++) {
				if (contains==false && predecessors[a]==from) {
					contains=true;
					if (a==0 && predecessors.length==1) {
						predecessors=null;
						return;
					} else {
						helper[a]=predecessors[a+1];
					}
				} else if (contains==true && a<helper.length) {
					helper[a]=predecessors[a+1];
				} else if (contains==true && a==helper.length) {
					return;
				} else {
					helper[a]=predecessors[a];
				}
			}
			predecessors = new Node[helper.length];
			for (int b=0; b<helper.length; b++) {
				predecessors[b]=helper[b];
			}
		}
	}
	
	public void setSuccessor(Node to) {
		if (successorEdgeCount==0) {
			successors=new Node[1];
			successors[0]=to;
		} else {
			Node []helper=new Node[successors.length+1];
			for (int a=0; a<successors.length; a++) {
				helper[a]=successors[a];
			}
			helper[successors.length]=to;
			successors=new Node[helper.length];
			for (int b=0; b<helper.length; b++) {
				successors[b]=helper[b];
			}
		}
		incrementSuccessors();
	}

	//because of absence of the possibility of overloading operators
	//this method compares two Nodes regarding to their  number
	//to get an output like:
	//-1 --> a smaller b
	//1 --> a greater b
	//0 --> a equals b
	public int compareTwoNodes(Node a, Node b) {
		if (a.number<b.number)
			return -1;
		if (a.number>b.number)
			return 1;
		return 0;
	}
	
	//required for the java.utils.Array.sort Method
	@Override
	public int compareTo(Node arg0) {
		//new new version --> sort nodes by predecessors
		if (predecessors.length==0 && arg0.predecessors.length==0) {
//			addNeighbor(arg0);
			return 0;
		}
		if (predecessors.length==0 && arg0.predecessors.length!=0)
			return -1;
		if (predecessors.length!=0 && arg0.predecessors.length==0)
			return 1;
		if (predecessors.length!=0 && arg0.predecessors.length!=0) {
			//TODO: (probably) the biggest (earlier: smallest) predecessor test is not the smartest way...
			int i=compareTwoNodes(getBiggestPredecessor(predecessors),arg0.getBiggestPredecessor(arg0.predecessors));
			switch (i) {
			case -1:
				return -1;
			case 1:
				return 1;
			case 0:
//				addNeighbor(arg0);
				return 0;
			}
		}
//		addNeighbor(arg0);
		return 0;
	}
}